home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectInput / MultiMapper / MultiMapper.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  40.9 KB  |  1,040 lines

  1. //-----------------------------------------------------------------------------
  2. // File: MultiMapper.cpp
  3. //
  4. // Desc: This is a simple sample to demonstrate how to code using the DInput
  5. //       action mapper feature.
  6. //
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #define DIRECTINPUT_VERSION 0x0800
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <math.h>
  13. #include <stdio.h>
  14. #include <DXErr8.h>
  15. #include <tchar.h>
  16. #include <dinput.h>
  17. #include "MultiDI.h"
  18. #include "DXUtil.h"
  19. #include "resource.h"
  20.  
  21.  
  22.  
  23.  
  24. //-----------------------------------------------------------------------------
  25. // Defines, and constants
  26. //-----------------------------------------------------------------------------
  27. #define SAMPLE_KEY        TEXT("Software\\Microsoft\\DirectX SDK\\MultiMapper")
  28.  
  29. // This GUID must be unique for every game, and the same for 
  30. // every instance of this app.  // {67131584-2938-4857-8A2E-D99DC2C82068}
  31. // The GUID allows DirectInput to remember input settings
  32. GUID g_guidApp = { 0x67131584, 0x2938, 0x4857, { 0x8a, 0x2e, 0xd9, 0x9d, 0xc2, 0xc8, 0x20, 0x68 } };
  33.  
  34.  
  35. // DirectInput action mapper reports events only when buttons/axis change
  36. // so we need to remember the present state of relevant axis/buttons for 
  37. // each DirectInput device.  The CMultiplayerInputDeviceManager will store a 
  38. // pointer for each device that points to this struct
  39. struct InputDeviceState
  40. {
  41.     FLOAT fAxisMoveUD;
  42.     BOOL  bButtonForwardThrust;
  43.     BOOL  bButtonReverseThrust;
  44.  
  45.     FLOAT fAxisRotateLR;
  46.     BOOL  bButtonRotateLeft;
  47.     BOOL  bButtonRotateRight;
  48.  
  49.     BOOL  bButtonFireWeapons;
  50.     BOOL  bButtonEnableShield;
  51. };
  52.  
  53.  
  54. // Struct to store the current input state
  55. struct UserInput
  56. {
  57.     FLOAT fAxisMoveUD;
  58.     FLOAT fAxisRotateLR;
  59.     BOOL  bButtonFireWeapons;
  60.     BOOL  bButtonEnableShield;
  61.  
  62.     BOOL  bDoConfigureInput;
  63.     BOOL  bDoQuitGame;
  64. };
  65.  
  66.  
  67. // Input semantics used by this app
  68. enum INPUT_SEMANTICS
  69. {
  70.     // Gameplay semantics
  71.     INPUT_ROTATE_AXIS_LR=1,  INPUT_MOVE_AXIS_UD,       
  72.     INPUT_FIREWEAPONS,       INPUT_ENABLESHIELD,    
  73.     INPUT_TURNLEFT,          INPUT_TURNRIGHT, 
  74.     INPUT_FORWARDTHRUST,     INPUT_REVERSETHRUST,
  75.     INPUT_DISPLAYGAMEMENU,   INPUT_QUITGAME,
  76. };
  77.  
  78. // Actions used by this app
  79. DIACTION g_rgGameAction[] =
  80. {
  81.     // If DirectInput has already been given an action map for this GUID, it
  82.     // will have created a user map for this application 
  83.     // (C:\Program Files\DirectX\DirectInput\User Maps\*.ini). If a user map
  84.     // exists, DirectInput will use the action map defined in the stored user 
  85.     // map instead of the map defined in your program. This allows the user to
  86.     // customize controls without losing changes when the game restarts. If you 
  87.     // wish to make changes to the default action map without changing the 
  88.     // GUID, you will need to delete the stored user map from your hard drive
  89.     // for the system to detect your changes and recreate a stored user map.
  90.     
  91.     // Device input (joystick, etc.) that is pre-defined by DInput, according
  92.     // to genre type. The genre for this app is space simulators.
  93.     { INPUT_ROTATE_AXIS_LR,  DIAXIS_SPACESIM_LATERAL,      0, TEXT("Turn left/right"), },
  94.     { INPUT_MOVE_AXIS_UD,    DIAXIS_SPACESIM_MOVE,         0, TEXT("Move"), },
  95.     { INPUT_FIREWEAPONS,     DIBUTTON_SPACESIM_FIRE,       0, TEXT("Shoot"), },
  96.     { INPUT_ENABLESHIELD,    DIBUTTON_SPACESIM_GEAR,       0, TEXT("Shield"), },
  97.     { INPUT_DISPLAYGAMEMENU, DIBUTTON_SPACESIM_DISPLAY,    0, TEXT("Configure"), },
  98.  
  99.     // Keyboard input mappings
  100.     { INPUT_TURNLEFT,        DIKEYBOARD_LEFT,    0, TEXT("Turn left"), },
  101.     { INPUT_TURNRIGHT,       DIKEYBOARD_RIGHT,   0, TEXT("Turn right"), },
  102.     { INPUT_FORWARDTHRUST,   DIKEYBOARD_UP,      0, TEXT("Move forward"), },
  103.     { INPUT_REVERSETHRUST,   DIKEYBOARD_DOWN,    0, TEXT("Move backward"), },
  104.     { INPUT_FIREWEAPONS,     DIKEYBOARD_F,       0, TEXT("Fire weapons"), },
  105.     { INPUT_ENABLESHIELD,    DIKEYBOARD_S,       0, TEXT("Enable shields"), },
  106.     { INPUT_DISPLAYGAMEMENU, DIKEYBOARD_D,       DIA_APPFIXED, TEXT("Configure"), },
  107.     { INPUT_QUITGAME,        DIKEYBOARD_ESCAPE,  DIA_APPFIXED, TEXT("Quit game"), },
  108.  
  109.     // Mouse input mappings
  110.     { INPUT_ROTATE_AXIS_LR,  DIMOUSE_XAXIS,      0, _T("Turn left/right"), },
  111.     { INPUT_MOVE_AXIS_UD,    DIMOUSE_YAXIS,      0, _T("Move"), },
  112.     { INPUT_FIREWEAPONS,     DIMOUSE_BUTTON0,    0, _T("Shoot"), },
  113.     { INPUT_ENABLESHIELD,    DIMOUSE_BUTTON1,    0, _T("Enable shields"), },
  114. };
  115.  
  116. #define NUMBER_OF_GAMEACTIONS    (sizeof(g_rgGameAction)/sizeof(DIACTION))
  117.  
  118.  
  119.  
  120.  
  121. //-----------------------------------------------------------------------------
  122. // Function prototypes 
  123. //-----------------------------------------------------------------------------
  124. INT_PTR CALLBACK StaticMsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  125.  
  126.  
  127.  
  128.  
  129. //-----------------------------------------------------------------------------
  130. // Name: class CMyApplication 
  131. // Desc: Application class.
  132. //-----------------------------------------------------------------------------
  133. class CMyApplication 
  134. {
  135.     TCHAR*                  m_strWindowTitle;       // Title for the app's window
  136.     HWND                    m_hWnd;                 // The main app window
  137.     FLOAT                   m_fTime;                // Current time in seconds
  138.     FLOAT                   m_fElapsedTime;         // Time elapsed since last frame
  139.  
  140.     CMultiplayerInputDeviceManager* m_pInputDeviceManager;  // DirectInput multiplayer device manager
  141.     DIACTIONFORMAT          m_diafGame;             // Action format for game play
  142.     UserInput               m_UserInput[4];         // Struct for storing user input 
  143.  
  144.     DWORD                   m_dwNumPlayers;         // Number of players in the game
  145.     FLOAT                   m_fWorldRotX;           // World rotation state X-axis
  146.     FLOAT                   m_fWorldRotY;           // World rotation state Y-axis
  147.  
  148. protected:
  149.     HRESULT OneTimeSceneInit();
  150.     HRESULT Render();
  151.     HRESULT FrameMove();
  152.     HRESULT FinalCleanup();
  153.  
  154.     HRESULT EnableUI();
  155.     HRESULT RenderText();
  156.     
  157.     HRESULT InitInput();
  158.     HRESULT ChangeNumPlayers( DWORD dwNumPlayers, BOOL bResetOwnership, BOOL bResetMappings );
  159.     VOID    ConfigInput();
  160.     void    UpdateInput();
  161.     void    CleanupDirectInput();
  162.     void    CleanupDeviceStateStructs();
  163.         
  164. public:
  165.     HRESULT Create( HINSTANCE hInstance );
  166.     INT     Run();
  167.     INT_PTR MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  168.  
  169.     CMyApplication();
  170.  
  171.     HRESULT InputAddDeviceCB( CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi );
  172.     static HRESULT CALLBACK StaticInputAddDeviceCB( CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi, LPVOID pParam );   
  173. };
  174.  
  175.  
  176.  
  177.  
  178. //-----------------------------------------------------------------------------
  179. // Global access to the app (needed for the global WndProc())
  180. //-----------------------------------------------------------------------------
  181. CMyApplication*    g_pApp  = NULL;
  182. HINSTANCE          g_hInst = NULL;
  183.  
  184.  
  185.  
  186.  
  187. //-----------------------------------------------------------------------------
  188. // Name: WinMain()
  189. // Desc: Application entry point
  190. //-----------------------------------------------------------------------------
  191. INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
  192. {
  193.     CMyApplication app;
  194.  
  195.     g_hInst = hInstance;
  196.  
  197.     if( FAILED( app.Create( hInstance ) ) )
  198.         return 0;
  199.  
  200.     return app.Run();
  201. }
  202.  
  203.  
  204.  
  205.  
  206. //-----------------------------------------------------------------------------
  207. // Name: CMyApplication()
  208. // Desc: Constructor
  209. //-----------------------------------------------------------------------------
  210. CMyApplication::CMyApplication()
  211. {
  212.     g_pApp                      = this;
  213.     m_hWnd                      = NULL;
  214.     m_strWindowTitle            = TEXT( "DirectInput MultiMapper Sample" );
  215.     m_pInputDeviceManager       = NULL;
  216.  
  217.     ZeroMemory( m_UserInput, sizeof(UserInput)*4 );
  218.     m_fWorldRotX                = 0.0f;
  219.     m_fWorldRotY                = 0.0f;
  220.     m_dwNumPlayers              = 1;
  221. }
  222.  
  223.  
  224.  
  225.  
  226. //-----------------------------------------------------------------------------
  227. // Name: Create()
  228. // Desc: Creates the window
  229. //-----------------------------------------------------------------------------
  230. HRESULT CMyApplication::Create( HINSTANCE hInstance )
  231. {
  232.     // Display the main dialog box.
  233.     CreateDialog( hInstance, MAKEINTRESOURCE(IDD_MAIN), 
  234.                   NULL, StaticMsgProc );
  235.     if( NULL == m_hWnd )
  236.         return E_FAIL;
  237.  
  238.     // Initialize the application timer
  239.     DXUtil_Timer( TIMER_START );
  240.  
  241.     return S_OK;
  242. }
  243.  
  244.  
  245.  
  246.  
  247. //-----------------------------------------------------------------------------
  248. // Name: Run()
  249. // Desc: Handles the message loop and calls FrameMove() and Render() when
  250. //       idle.
  251. //-----------------------------------------------------------------------------
  252. INT CMyApplication::Run()
  253. {
  254.     MSG msg;
  255.  
  256.     // Message loop to run the app
  257.     while( TRUE )
  258.     {
  259.         if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  260.         {
  261.             // Skip WM_KEYDOWN so they aren't handled by the dialog
  262.             if( msg.message == WM_KEYDOWN )
  263.                 continue;
  264.  
  265.             if( !IsDialogMessage( m_hWnd, &msg ) )  
  266.             {
  267.                 TranslateMessage( &msg );
  268.                 DispatchMessage( &msg );
  269.             }
  270.  
  271.             if( msg.message == WM_QUIT )
  272.             {
  273.                 DestroyWindow( m_hWnd );
  274.                 break;
  275.             }
  276.         }
  277.         else
  278.         {
  279.             // Update the time variables
  280.             m_fTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  281.             m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  282.  
  283.             // This app uses idle time processing for the game loop
  284.             if( FAILED( FrameMove() ) )
  285.                 SendMessage( m_hWnd, WM_DESTROY, 0, 0 );
  286.             if( FAILED( Render() ) ) 
  287.                 SendMessage( m_hWnd, WM_DESTROY, 0, 0 );
  288.  
  289.             Sleep( 20 );
  290.         }
  291.     }
  292.  
  293.     FinalCleanup();
  294.  
  295.     return (INT)msg.wParam;
  296. }
  297.  
  298.  
  299.  
  300.  
  301. //-----------------------------------------------------------------------------
  302. // Name: OneTimeSceneInit()
  303. // Desc: Called during initial app startup, this function performs all the
  304. //       permanent initialization.
  305. //-----------------------------------------------------------------------------
  306. HRESULT CMyApplication::OneTimeSceneInit()
  307. {
  308.     HRESULT hr;
  309.     
  310.     // Load the icon
  311.     HICON hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE( IDI_MAIN ) );
  312.     
  313.     // Set the icon for this dialog.
  314.     SendMessage( m_hWnd, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  315.     SendMessage( m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  316.     
  317.     // Initialize DirectInput
  318.     if( FAILED( hr = InitInput() ) )
  319.         return DXTRACE_ERR( TEXT("InitInput"), hr );
  320.     
  321.     HWND hNumPlayers = GetDlgItem( m_hWnd, IDC_NUM_PLAYERS_COMBO );
  322.     SendMessage( hNumPlayers, CB_ADDSTRING, 0, (LPARAM) TEXT("1") );
  323.     SendMessage( hNumPlayers, CB_ADDSTRING, 0, (LPARAM) TEXT("2") );
  324.     SendMessage( hNumPlayers, CB_ADDSTRING, 0, (LPARAM) TEXT("3") );
  325.     SendMessage( hNumPlayers, CB_ADDSTRING, 0, (LPARAM) TEXT("4") );
  326.     SendMessage( hNumPlayers, CB_SETCURSEL, m_dwNumPlayers-1, 0 );
  327.  
  328.     EnableUI();
  329.     
  330.     return S_OK;
  331. }
  332.  
  333.  
  334.  
  335.  
  336. //-----------------------------------------------------------------------------
  337. // Name: InitInput()
  338. // Desc: Initialize DirectInput objects
  339. //-----------------------------------------------------------------------------
  340. HRESULT CMyApplication::InitInput()
  341. {
  342.     HRESULT hr;
  343.  
  344.     // Setup action format for the actual gameplay
  345.     ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
  346.     m_diafGame.dwSize          = sizeof(DIACTIONFORMAT);
  347.     m_diafGame.dwActionSize    = sizeof(DIACTION);
  348.     m_diafGame.dwDataSize      = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
  349.     m_diafGame.guidActionMap   = g_guidApp;
  350.     m_diafGame.dwGenre         = DIVIRTUAL_SPACESIM; 
  351.     m_diafGame.dwNumActions    = NUMBER_OF_GAMEACTIONS;
  352.     m_diafGame.rgoAction       = g_rgGameAction;
  353.     m_diafGame.lAxisMin        = -100;
  354.     m_diafGame.lAxisMax        = 100;
  355.     m_diafGame.dwBufferSize    = 16;
  356.     _tcscpy( m_diafGame.tszActionMap, _T("MultiMapper Sample") );
  357.     
  358.     // Create a new input device manager
  359.     m_pInputDeviceManager = new CMultiplayerInputDeviceManager( SAMPLE_KEY );
  360.  
  361.     if( FAILED( hr = ChangeNumPlayers( 1, FALSE, FALSE ) ) )
  362.         return DXTRACE_ERR( TEXT("ChangeNumPlayers"), hr );
  363.     
  364.     return S_OK;
  365. }
  366.  
  367.  
  368.  
  369.  
  370. //-----------------------------------------------------------------------------
  371. // Name: StaticInputAddDeviceCB()
  372. // Desc: Static callback helper to call into CMyApplication class
  373. //-----------------------------------------------------------------------------
  374. HRESULT CALLBACK CMyApplication::StaticInputAddDeviceCB( 
  375.                                          CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, 
  376.                                          CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, 
  377.                                          const DIDEVICEINSTANCE* pdidi, 
  378.                                          LPVOID pParam )
  379. {
  380.     CMyApplication* pApp = (CMyApplication*) pParam;
  381.     return pApp->InputAddDeviceCB( pPlayerInfo, pDeviceInfo, pdidi );
  382. }
  383.  
  384.  
  385.  
  386.  
  387. //-----------------------------------------------------------------------------
  388. // Name: InputAddDeviceCB()
  389. // Desc: Called from CMultiplayerInputDeviceManager whenever a device is added. 
  390. //       Set the dead zone, and creates a new InputDeviceState for each device
  391. //-----------------------------------------------------------------------------
  392. HRESULT CMyApplication::InputAddDeviceCB( CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, 
  393.                                          CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, 
  394.                                          const DIDEVICEINSTANCE* pdidi )
  395. {
  396.     if( (GET_DIDEVICE_TYPE(pdidi->dwDevType) != DI8DEVTYPE_KEYBOARD) &&
  397.         (GET_DIDEVICE_TYPE(pdidi->dwDevType) != DI8DEVTYPE_MOUSE) )
  398.     {
  399.         // Setup the deadzone 
  400.         DIPROPDWORD dipdw;
  401.         dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  402.         dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  403.         dipdw.diph.dwObj        = 0;
  404.         dipdw.diph.dwHow        = DIPH_DEVICE;
  405.         dipdw.dwData            = 500;
  406.         pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
  407.     }
  408.     
  409.     // Create a new InputDeviceState for each device so the 
  410.     // app can record its state 
  411.     InputDeviceState* pNewInputDeviceState = new InputDeviceState;
  412.     ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
  413.     pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
  414.             
  415.     HWND hPlayerDevice;
  416.     switch( pPlayerInfo->dwPlayerIndex )
  417.     {
  418.     case 0:
  419.         hPlayerDevice = GetDlgItem( m_hWnd, IDC_DEVICE_ASSIGNED_P1 );
  420.         break;
  421.     case 1:
  422.         hPlayerDevice = GetDlgItem( m_hWnd, IDC_DEVICE_ASSIGNED_P2 );
  423.         break;
  424.     case 2:
  425.         hPlayerDevice = GetDlgItem( m_hWnd, IDC_DEVICE_ASSIGNED_P3 );
  426.         break;
  427.     case 3:
  428.         hPlayerDevice = GetDlgItem( m_hWnd, IDC_DEVICE_ASSIGNED_P4 );
  429.         break;
  430.     }
  431.  
  432.     SendMessage( hPlayerDevice, LB_ADDSTRING, 0, (LPARAM) pdidi->tszProductName );
  433.     
  434.     return S_OK;
  435. }
  436.  
  437.  
  438.  
  439.  
  440. //-----------------------------------------------------------------------------
  441. // Name: ChangeNumPlayers()
  442. // Desc: Signals a change in the number of players. It is also called to reset
  443. //       ownership and mapping data.
  444. //-----------------------------------------------------------------------------
  445. HRESULT CMyApplication::ChangeNumPlayers( DWORD dwNumPlayers, BOOL bResetOwnership, 
  446.                                           BOOL bResetMappings )
  447. {
  448.     HRESULT hr;
  449.     
  450.     m_dwNumPlayers = dwNumPlayers;
  451.  
  452.     // Just pass in stock names.  Real games may want to ask the user for a name, etc.
  453.     TCHAR* strUserNames[4] = { TEXT("Player 1"), TEXT("Player 2"), 
  454.                                TEXT("Player 3"), TEXT("Player 4") };
  455.  
  456.     BOOL bSuccess = FALSE;
  457.     while( !bSuccess )
  458.     {
  459.         // Update UI
  460.         EnableUI();    
  461.         SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P1), LB_RESETCONTENT, 0, 0 );
  462.         SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P2), LB_RESETCONTENT, 0, 0 );
  463.         SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P3), LB_RESETCONTENT, 0, 0 );
  464.         SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P4), LB_RESETCONTENT, 0, 0 );
  465.         
  466.         hr = m_pInputDeviceManager->Create( m_hWnd, strUserNames, m_dwNumPlayers, &m_diafGame, 
  467.                                             StaticInputAddDeviceCB, this, 
  468.                                             bResetOwnership, bResetMappings );
  469.  
  470.         if( FAILED(hr) )
  471.         {
  472.             switch( hr )
  473.             {
  474.                 case E_DIUTILERR_DEVICESTAKEN:
  475.                 {
  476.                     // It's possible that a single user could "own" too many devices for the other
  477.                     // players to get into the game. If so, we reinit the manager class to provide 
  478.                     // each user with a device that has a default configuration.
  479.                     bResetOwnership = TRUE;
  480.                     
  481.                     MessageBox( m_hWnd, TEXT("You have entered more users than there are suitable ")       \
  482.                                         TEXT("devices, or some users are claiming too many devices.\n") \
  483.                                         TEXT("Press OK to give each user a default device"), 
  484.                                         TEXT("Devices Are Taken"), MB_OK | MB_ICONEXCLAMATION );
  485.                     break;
  486.                 }
  487.                     
  488.                 case E_DIUTILERR_TOOMANYUSERS:
  489.                 {
  490.                     // Another common error is if more users are attempting to play than there are devices
  491.                     // attached to the machine. In this case, the number of players is automatically 
  492.                     // lowered to make playing the game possible. 
  493.                     DWORD dwNumDevices = m_pInputDeviceManager->GetNumDevices();
  494.                     m_dwNumPlayers = dwNumDevices;                    
  495.                     SendMessage( GetDlgItem( m_hWnd, IDC_NUM_PLAYERS_COMBO ), 
  496.                                  CB_SETCURSEL, m_dwNumPlayers-1, 0 );
  497.                                 
  498.                     TCHAR sz[256];
  499.                     wsprintf( sz, TEXT("There are not enough devices attached to the ")          \
  500.                                   TEXT("system for the number of users you entered.\nThe ")      \
  501.                                   TEXT("number of users has been automatically changed to ")     \
  502.                                   TEXT("%i (the number of devices available on the system)."),
  503.                                   m_dwNumPlayers );
  504.                     MessageBox( m_hWnd, sz, _T("Too Many Users"), MB_OK | MB_ICONEXCLAMATION );                    
  505.                     break;
  506.                 }
  507.  
  508.                 default:
  509.                     return DXTRACE_ERR( TEXT("m_pInputDeviceManager->Create"), hr );
  510.                     break;
  511.             }
  512.             
  513.             m_pInputDeviceManager->Cleanup();                                
  514.         }
  515.         else
  516.         {
  517.             bSuccess = TRUE;
  518.         }
  519.     }
  520.     
  521.     return S_OK;
  522. }
  523.  
  524.  
  525.  
  526.  
  527. //-----------------------------------------------------------------------------
  528. // Name: FrameMove()
  529. // Desc: Called once per frame, the call is the entry point for animating
  530. //       the scene.
  531. //-----------------------------------------------------------------------------
  532. HRESULT CMyApplication::FrameMove()
  533. {
  534.     // Update user input state
  535.     UpdateInput();
  536.     
  537.     for( DWORD iPlayer=0; iPlayer<m_dwNumPlayers; iPlayer++ )
  538.     {       
  539.         // Respond to input
  540.         if( m_UserInput[iPlayer].bDoConfigureInput )
  541.         {
  542.             // One-shot per keypress
  543.             m_UserInput[iPlayer].bDoConfigureInput = FALSE;
  544.  
  545.             ConfigInput();
  546.         }
  547.     
  548.         // Update the world state according to user input
  549.         if( m_UserInput[iPlayer].fAxisMoveUD )
  550.             m_fWorldRotY += m_fElapsedTime * m_UserInput[iPlayer].fAxisMoveUD;
  551.     
  552.         if( m_UserInput[iPlayer].fAxisRotateLR )
  553.             m_fWorldRotX += m_fElapsedTime * m_UserInput[iPlayer].fAxisRotateLR;
  554.     }
  555.     
  556.     return S_OK;
  557. }
  558.  
  559.  
  560.  
  561.  
  562. //-----------------------------------------------------------------------------
  563. // Name: UpdateInput()
  564. // Desc: Update the user input.  Called once per frame 
  565. //-----------------------------------------------------------------------------
  566. void CMyApplication::UpdateInput()
  567. {
  568.     if( NULL == m_pInputDeviceManager )
  569.         return;
  570.     
  571.     CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfos;
  572.     DWORD dwNumDevices;
  573.  
  574.     // Get access to the list of semantically-mapped input devices
  575.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  576.  
  577.     // Loop through all devices and check game input
  578.     for( DWORD i=0; i<dwNumDevices; i++ )
  579.     {
  580.         // skip past any devices that aren't assigned, 
  581.         // since we don't care about them
  582.         if( pDeviceInfos[i].pPlayerInfo == NULL )
  583.             continue;
  584.  
  585.         DIDEVICEOBJECTDATA rgdod[10];
  586.         DWORD   dwItems = 10;
  587.         HRESULT hr;
  588.         LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
  589.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  590.         FLOAT fScale = 1.0f;
  591.  
  592.         if( pDeviceInfos[i].bRelativeAxis )
  593.         {
  594.             // For relative axis data, the action mapper only informs us when
  595.             // the delta data is non-zero, so we need to zero its state
  596.             // out each frame
  597.             pInputDeviceState->fAxisMoveUD   = 0.0f;
  598.             pInputDeviceState->fAxisRotateLR = 0.0f;      
  599.  
  600.             // Scale the relative axis data to make it more equal to 
  601.             // absolute joystick data
  602.             fScale = 5.0f;
  603.         }
  604.  
  605.         hr = pdidDevice->Acquire();
  606.         hr = pdidDevice->Poll();
  607.         hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  608.                                         rgdod, &dwItems, 0 );
  609.         if( FAILED(hr) )
  610.             continue;
  611.  
  612.         // Get the sematics codes for the game menu
  613.         for( DWORD j=0; j<dwItems; j++ )
  614.         {
  615.             BOOL  bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
  616.             FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
  617.             FLOAT fAxisState   = (FLOAT)((int)rgdod[j].dwData)/100.0f * fScale;
  618.  
  619.             switch( rgdod[j].uAppData )
  620.             {
  621.                 // Handle relative axis data
  622.                 case INPUT_ROTATE_AXIS_LR: 
  623.                     pInputDeviceState->fAxisRotateLR = fAxisState;
  624.                     break;
  625.                 case INPUT_MOVE_AXIS_UD:
  626.                     pInputDeviceState->fAxisMoveUD = -fAxisState;
  627.                     break;
  628.  
  629.                 // Handle buttons separately so the button state data
  630.                 // doesn't overwrite the axis state data, and handle
  631.                 // each button separately so they don't overwrite each other
  632.                 case INPUT_TURNLEFT:        pInputDeviceState->bButtonRotateLeft    = bButtonState; break;
  633.                 case INPUT_TURNRIGHT:       pInputDeviceState->bButtonRotateRight   = bButtonState; break;
  634.                 case INPUT_FORWARDTHRUST:   pInputDeviceState->bButtonForwardThrust = bButtonState; break;
  635.                 case INPUT_REVERSETHRUST:   pInputDeviceState->bButtonReverseThrust = bButtonState; break;
  636.                 case INPUT_FIREWEAPONS:     pInputDeviceState->bButtonFireWeapons   = bButtonState; break;
  637.                 case INPUT_ENABLESHIELD:    pInputDeviceState->bButtonEnableShield  = bButtonState; break;
  638.  
  639.                 // Handle one-shot buttons
  640.                 case INPUT_DISPLAYGAMEMENU: if( bButtonState ) m_UserInput[0].bDoConfigureInput = TRUE; break;
  641.                 case INPUT_QUITGAME:        if( bButtonState ) m_UserInput[0].bDoQuitGame       = TRUE; break;
  642.             }
  643.         }
  644.     }
  645.  
  646.     for( DWORD iPlayer=0; iPlayer<m_dwNumPlayers; iPlayer++ )
  647.     {       
  648.         // Process user input and store result into pUserInput struct
  649.         m_UserInput[iPlayer].fAxisRotateLR = 0.0f;
  650.         m_UserInput[iPlayer].fAxisMoveUD   = 0.0f;
  651.         m_UserInput[iPlayer].bButtonFireWeapons  = FALSE;
  652.         m_UserInput[iPlayer].bButtonEnableShield = FALSE;
  653.  
  654.         // Concatinate the data from all the DirectInput devices
  655.         for( i=0; i<dwNumDevices; i++ )
  656.         {
  657.             // Only look at devices that are assigned to this player 
  658.             if( pDeviceInfos[i].pPlayerInfo == NULL || 
  659.                 pDeviceInfos[i].pPlayerInfo->dwPlayerIndex != iPlayer )
  660.                 continue;
  661.  
  662.             InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  663.  
  664.             // Use the axis data that is furthest from zero
  665.             if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(m_UserInput[iPlayer].fAxisRotateLR) )
  666.                 m_UserInput[iPlayer].fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
  667.  
  668.             if( fabs(pInputDeviceState->fAxisMoveUD) > fabs(m_UserInput[iPlayer].fAxisMoveUD) )
  669.                 m_UserInput[iPlayer].fAxisMoveUD = pInputDeviceState->fAxisMoveUD;
  670.  
  671.             // Process the button data 
  672.             if( pInputDeviceState->bButtonRotateLeft )
  673.                 m_UserInput[iPlayer].fAxisRotateLR = -1.0f;
  674.             else if( pInputDeviceState->bButtonRotateRight )
  675.                 m_UserInput[iPlayer].fAxisRotateLR = 1.0f;
  676.  
  677.             if( pInputDeviceState->bButtonForwardThrust )
  678.                 m_UserInput[iPlayer].fAxisMoveUD = 1.0f;
  679.             else if( pInputDeviceState->bButtonReverseThrust )
  680.                 m_UserInput[iPlayer].fAxisMoveUD = -1.0f;
  681.  
  682.             if( pInputDeviceState->bButtonFireWeapons )
  683.                 m_UserInput[iPlayer].bButtonFireWeapons = TRUE;
  684.             if( pInputDeviceState->bButtonEnableShield )
  685.                 m_UserInput[iPlayer].bButtonEnableShield = TRUE;
  686.         } 
  687.     }
  688. }
  689.  
  690.  
  691.  
  692.  
  693. //-----------------------------------------------------------------------------
  694. // Name: Render()
  695. // Desc: Called once per frame, the call is the entry point for rendering the 
  696. //       world.
  697. //-----------------------------------------------------------------------------
  698. HRESULT CMyApplication::Render()
  699. {
  700.     TCHAR szMsg[MAX_PATH];
  701.     TCHAR szMsgCurrent[MAX_PATH];
  702.  
  703.     // Update Player 1
  704.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput[0].fAxisMoveUD );
  705.     GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P1), szMsgCurrent, MAX_PATH );
  706.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  707.         SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P1), szMsg );
  708.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput[0].fAxisRotateLR );
  709.     GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P1), szMsgCurrent, MAX_PATH );
  710.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  711.         SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P1), szMsg );
  712.     if( !m_UserInput[0].bButtonEnableShield && !m_UserInput[0].bButtonFireWeapons )
  713.         _stprintf( szMsg, TEXT("None") );
  714.     else
  715.         _stprintf( szMsg, TEXT("%s%s"), m_UserInput[0].bButtonEnableShield ? TEXT("Shield ") : TEXT(""), 
  716.                                       m_UserInput[0].bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
  717.     GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P1), szMsgCurrent, MAX_PATH );
  718.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  719.         SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P1), szMsg );
  720.  
  721.     // Update Player 2
  722.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput[1].fAxisMoveUD );
  723.     GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P2), szMsgCurrent, MAX_PATH );
  724.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  725.         SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P2), szMsg );
  726.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput[1].fAxisRotateLR );
  727.     GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P2), szMsgCurrent, MAX_PATH );
  728.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  729.         SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P2), szMsg );
  730.     if( !m_UserInput[1].bButtonEnableShield && !m_UserInput[1].bButtonFireWeapons )
  731.         _stprintf( szMsg, TEXT("None") );
  732.     else
  733.         _stprintf( szMsg, TEXT("%s%s"), m_UserInput[1].bButtonEnableShield ? TEXT("Shield ") : TEXT(""), 
  734.         m_UserInput[1].bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
  735.     GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P2), szMsgCurrent, MAX_PATH );
  736.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  737.         SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P2), szMsg );
  738.     
  739.     // Update Player 3
  740.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput[2].fAxisMoveUD );
  741.     GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P3), szMsgCurrent, MAX_PATH );
  742.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  743.         SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P3), szMsg );
  744.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput[2].fAxisRotateLR );
  745.     GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P3), szMsgCurrent, MAX_PATH );
  746.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  747.         SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P3), szMsg );
  748.     if( !m_UserInput[2].bButtonEnableShield && !m_UserInput[2].bButtonFireWeapons )
  749.         _stprintf( szMsg, TEXT("None") );
  750.     else
  751.         _stprintf( szMsg, TEXT("%s%s"), m_UserInput[2].bButtonEnableShield ? TEXT("Shield ") : TEXT(""), 
  752.         m_UserInput[2].bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
  753.     GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P3), szMsgCurrent, MAX_PATH );
  754.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  755.         SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P3), szMsg );
  756.     
  757.     // Update Player 4
  758.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput[3].fAxisMoveUD );
  759.     GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P4), szMsgCurrent, MAX_PATH );
  760.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  761.         SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P4), szMsg );
  762.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput[3].fAxisRotateLR );
  763.     GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P4), szMsgCurrent, MAX_PATH );
  764.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  765.         SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P4), szMsg );
  766.     if( !m_UserInput[3].bButtonEnableShield && !m_UserInput[3].bButtonFireWeapons )
  767.         _stprintf( szMsg, TEXT("None") );
  768.     else
  769.         _stprintf( szMsg, TEXT("%s%s"), m_UserInput[3].bButtonEnableShield ? TEXT("Shield ") : TEXT(""), 
  770.         m_UserInput[3].bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
  771.     GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P4), szMsgCurrent, MAX_PATH );
  772.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  773.         SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P4), szMsg );      
  774.     
  775.     // Update world state
  776.     _stprintf( szMsg, TEXT("%0.3f, %0.3f"), m_fWorldRotX, m_fWorldRotY );
  777.     GetWindowText( GetDlgItem(m_hWnd,IDC_WORLD_STATE), szMsgCurrent, MAX_PATH );
  778.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  779.         SetWindowText( GetDlgItem(m_hWnd,IDC_WORLD_STATE), szMsg );
  780.  
  781.     return S_OK;
  782. }
  783.  
  784.  
  785.  
  786.  
  787. //-----------------------------------------------------------------------------
  788. // Name: StaticMsgProc()
  789. // Desc: Static msg handler which passes messages to the application class.
  790. //-----------------------------------------------------------------------------
  791. INT_PTR CALLBACK StaticMsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  792. {
  793.     return g_pApp->MsgProc( hWnd, uMsg, wParam, lParam );
  794. }
  795.  
  796.  
  797.  
  798.  
  799. //-----------------------------------------------------------------------------
  800. // Name: MsgProc()
  801. // Desc: Callback for all Windows messages
  802. //-----------------------------------------------------------------------------
  803. INT_PTR CMyApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  804. {
  805.     HRESULT hr;
  806.  
  807.     switch( msg )
  808.     {
  809.         case WM_INITDIALOG:
  810.             m_hWnd = hWnd;
  811.  
  812.             // Initialize the app's custom scene stuff
  813.             if( FAILED( hr = OneTimeSceneInit() ) )
  814.             {
  815.                 DXTRACE_ERR( TEXT("OneTimeSceneInit"), hr );
  816.                 MessageBox( hWnd, TEXT("Error initializing DirectInput.  Sample will now exit."), 
  817.                             TEXT("DirectInput Sample"), MB_OK | MB_ICONERROR );
  818.                 PostQuitMessage( IDCANCEL );
  819.                 return TRUE;
  820.             }
  821.             break;
  822.             
  823.         case WM_COMMAND:
  824.         {
  825.             switch( LOWORD(wParam) )
  826.             {
  827.             case IDC_NUM_PLAYERS_COMBO:
  828.                 {
  829.                     if( HIWORD(wParam) == CBN_SELCHANGE )
  830.                     {
  831.                         TCHAR strItem[MAX_PATH];
  832.                         HWND hNumPlayers = GetDlgItem( m_hWnd, IDC_NUM_PLAYERS_COMBO );
  833.                     
  834.                         int nCurSel = (int) SendMessage( hNumPlayers, CB_GETCURSEL, 0, 0 );
  835.                         SendMessage( hNumPlayers, CB_GETLBTEXT, nCurSel, (LPARAM) strItem );
  836.                         DWORD dwNumPlayers = _ttoi( strItem );
  837.  
  838.                         if( FAILED( hr = ChangeNumPlayers( dwNumPlayers, FALSE, FALSE ) ) )
  839.                         {
  840.                             PostQuitMessage( IDCANCEL );                            
  841.                         }
  842.                     }
  843.                     break;
  844.                 }
  845.  
  846.                 case IDC_RESET_OWNERSHIP:
  847.                     ChangeNumPlayers( m_dwNumPlayers, TRUE, FALSE );
  848.                     break;
  849.                 
  850.                 case IDC_RESET_MAPPINGS:
  851.                     ChangeNumPlayers( m_dwNumPlayers, FALSE, TRUE );
  852.                     break;
  853.                 
  854.                 case IDCANCEL:
  855.                     PostQuitMessage( IDCANCEL );
  856.                     break;
  857.  
  858.                 case IDM_CONFIGINPUT:
  859.                     m_UserInput[0].bDoConfigureInput = TRUE;
  860.                     break;
  861.             }
  862.             break;
  863.         }
  864.     }
  865.     
  866.     return FALSE;
  867. }
  868.  
  869.  
  870.  
  871.  
  872. //-----------------------------------------------------------------------------
  873. // Name: FinalCleanup()
  874. // Desc: Called before the app exits, this function gives the app the chance
  875. //       to cleanup after itself.
  876. //-----------------------------------------------------------------------------
  877. HRESULT CMyApplication::FinalCleanup()
  878. {
  879.     // Cleanup DirectInput
  880.     CleanupDirectInput();
  881.     
  882.     return S_OK;
  883. }
  884.  
  885.  
  886.  
  887.  
  888. //-----------------------------------------------------------------------------
  889. // Name: CleanupDirectInput()
  890. // Desc: Cleanup DirectInput 
  891. //-----------------------------------------------------------------------------
  892. VOID CMyApplication::CleanupDirectInput()
  893. {
  894.     if( NULL == m_pInputDeviceManager )
  895.         return;
  896.     
  897.     CleanupDeviceStateStructs();
  898.     
  899.     // Cleanup DirectX input objects
  900.     SAFE_DELETE( m_pInputDeviceManager );
  901. }
  902.  
  903.  
  904.  
  905.  
  906. //-----------------------------------------------------------------------------
  907. // Name: CleanupDeviceStateStructs()
  908. // Desc: 
  909. //-----------------------------------------------------------------------------
  910. VOID CMyApplication::CleanupDeviceStateStructs()
  911. {
  912.     // Get access to the list of semantically-mapped input devices
  913.     // to delete all InputDeviceState structs before calling ConfigureDevices()
  914.     CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfos;
  915.     DWORD dwNumDevices;
  916.     
  917.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  918.  
  919.     for( DWORD i=0; i<dwNumDevices; i++ )
  920.     {
  921.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  922.         SAFE_DELETE( pInputDeviceState );
  923.         pDeviceInfos[i].pParam = NULL;
  924.     }
  925. }
  926.  
  927.  
  928.  
  929.  
  930. //-----------------------------------------------------------------------------
  931. // Name: ConfigInput()
  932. // Desc: 
  933. //-----------------------------------------------------------------------------
  934. VOID CMyApplication::ConfigInput()
  935. {
  936.     HRESULT hr;
  937.     
  938.     EnableWindow( m_hWnd, FALSE );
  939.  
  940.     CleanupDeviceStateStructs();
  941.     
  942.     // Update UI
  943.     EnableUI();    
  944.     SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P1), LB_RESETCONTENT, 0, 0 );
  945.     SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P2), LB_RESETCONTENT, 0, 0 );
  946.     SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P3), LB_RESETCONTENT, 0, 0 );
  947.     SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P4), LB_RESETCONTENT, 0, 0 );
  948.     
  949.     // Configure the devices (with edit capability)
  950.     hr = m_pInputDeviceManager->ConfigureDevices( m_hWnd, NULL, NULL, DICD_EDIT, NULL );    
  951.     if( FAILED(hr) )
  952.     {
  953.         if( hr == E_DIUTILERR_PLAYERWITHOUTDEVICE )
  954.         {
  955.             // There's a player that hasn't been assigned a device.  Some games may
  956.             // want to handle this by reducing the number of players, or auto-assigning
  957.             // a device, or warning the user, etc.
  958.             MessageBox( m_hWnd, TEXT("There is at least one player that wasn't assigned ") \
  959.                                 TEXT("a device\n") \
  960.                                 TEXT("Press OK to auto-assign a device to these users"), 
  961.                                 TEXT("Player Without Device"), MB_OK | MB_ICONEXCLAMATION );
  962.         }
  963.  
  964.         // Auto-reassign every player a device.
  965.         ChangeNumPlayers( m_dwNumPlayers, FALSE, FALSE );
  966.     }
  967.  
  968.     EnableWindow( m_hWnd, TRUE );
  969.     SetForegroundWindow( m_hWnd );
  970. }
  971.  
  972.  
  973.  
  974.  
  975. //-----------------------------------------------------------------------------
  976. // Name: EnableUI()
  977. // Desc: 
  978. //-----------------------------------------------------------------------------
  979. HRESULT CMyApplication::EnableUI()
  980. {
  981.     BOOL bEnablePlayer4 = ( m_dwNumPlayers > 3 );
  982.     BOOL bEnablePlayer3 = ( m_dwNumPlayers > 2 );
  983.     BOOL bEnablePlayer2 = ( m_dwNumPlayers > 1 );
  984.  
  985.     // Enable/disable the player 2 ui
  986.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT1_P2), bEnablePlayer2 );
  987.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT2_P2), bEnablePlayer2 );
  988.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT3_P2), bEnablePlayer2 );
  989.     EnableWindow( GetDlgItem(m_hWnd,IDC_PLAYER2_GROUP),    bEnablePlayer2 );
  990.     EnableWindow( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P2), bEnablePlayer2 );
  991.     EnableWindow( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P2), bEnablePlayer2 );
  992.     EnableWindow( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P2),  bEnablePlayer2 );
  993.     EnableWindow( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P2),  bEnablePlayer2 );
  994.     if( !bEnablePlayer2 )
  995.     {
  996.         SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P2), TEXT("n/a") );
  997.         SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P2), TEXT("n/a") );
  998.         SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P2),  TEXT("n/a") );
  999.     }
  1000.     
  1001.     // Enable/disable the player 3 ui
  1002.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT1_P3), bEnablePlayer3 );
  1003.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT2_P3), bEnablePlayer3 );
  1004.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT3_P3), bEnablePlayer3 );
  1005.     EnableWindow( GetDlgItem(m_hWnd,IDC_PLAYER3_GROUP),    bEnablePlayer3 );
  1006.     EnableWindow( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P3), bEnablePlayer3 );
  1007.     EnableWindow( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P3), bEnablePlayer3 );
  1008.     EnableWindow( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P3),  bEnablePlayer3 );
  1009.     EnableWindow( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P3),  bEnablePlayer3 );
  1010.     if( !bEnablePlayer4 )
  1011.     {
  1012.         SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P3), TEXT("n/a") );
  1013.         SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P3), TEXT("n/a") );
  1014.         SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P3),  TEXT("n/a") );
  1015.     }
  1016.     
  1017.     // Enable/disable the player 4 ui
  1018.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT1_P4), bEnablePlayer4 );
  1019.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT2_P4), bEnablePlayer4 );
  1020.     EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT3_P4), bEnablePlayer4 );
  1021.     EnableWindow( GetDlgItem(m_hWnd,IDC_PLAYER4_GROUP),    bEnablePlayer4 );
  1022.     EnableWindow( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P4), bEnablePlayer4 );
  1023.     EnableWindow( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P4), bEnablePlayer4 );
  1024.     EnableWindow( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P4),  bEnablePlayer4 );
  1025.     EnableWindow( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P4), bEnablePlayer4 );
  1026.     if( !bEnablePlayer4 )
  1027.     {
  1028.         SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P4), TEXT("n/a") );
  1029.         SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P4), TEXT("n/a") );
  1030.         SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P4),  TEXT("n/a") );
  1031.     }
  1032.     
  1033.     return S_OK;
  1034. }
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.